package edu.ncsu.csc.ip.routing.ls;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Comparator;

/**
 * Class <code>link_state</code>
 * 
 * Runs LinkState to comply with project 3 description
 * 
 * @author Moin Ayazifar <mayazif@ncsu.edu>
 * @author Steven Elliott <sdelliot@ncsu.edu>
 * 
 */

public class all_paths_with_demand_fraction {

	// public static final double ALPHA = 15;
	// public static final double BETA = 1.2;

	public static Comparator<Node> NodeNameComparator = new Comparator<Node>() {
		public int compare(Node node1, Node node2) {
			// ascending order
			return Integer.valueOf(node1.getName()).compareTo(
					Integer.valueOf(node2.getName()));
		}
	};

	public static void main(String[] args) throws IOException {

		Node source = null;
		String sourceString = null;
		String sasKFactFileAddress = "./results/SASKFact.txt";
		String sasDemandFileAddress = "./results/SASDemand.txt";
		String sasPathDemandFileAddress = "./results/SASPathDemand.txt";
		String humanFileAddress = "./results/HumanPathLink.txt";

		try {

			Double alpha = Double.parseDouble(args[2]);
			Double beta = Double.parseDouble(args[3]);

			File sasDemandFile = new File(sasDemandFileAddress);
			PrintWriter sasDemandPrintWriter = new PrintWriter(new FileWriter(
					sasDemandFile, false));

			File sasPathDemandFile = new File(sasPathDemandFileAddress);
			PrintWriter sasPathDemandPrintWriter = new PrintWriter(
					new FileWriter(sasPathDemandFile, false));

			File sasKFactFile = new File(sasKFactFileAddress);
			PrintWriter sasKFactPrintWriter = new PrintWriter(new FileWriter(
					sasKFactFile, false));

			sasKFactPrintWriter
					.println("Path_ID\tDemand_ID\tOrigin\t\tDestination\tP_Origin\tP_Destination\tkfact");

			sasPathDemandPrintWriter
					.println("Path_ID\tDemand_ID\tOrigin\tDestination");

			sasDemandPrintWriter.println("Demand_ID\tP_Origin\tP_Destination");

			File readableFile = new File(humanFileAddress);
			PrintWriter readablePrintWrite = new PrintWriter(new FileWriter(
					readableFile, false));

			// // For every source and destination

			File file;
			BufferedReader fileReader;

			System.out.println("Reading: " + args[1]);
			file = new File(args[1]);
			fileReader = new BufferedReader(new FileReader(file));
			String line;
			sourceString = null;
			long pathId = 0;
			long demandId = 0;
			while ((line = fileReader.readLine()) != null) {
				sourceString = null;
				String[] params = line.split("\\s+");
				if (params.length > 2) {
					sourceString = params[0];
					System.out.println("From: " + sourceString + " To:");
					int n = (params.length - 1) / 2;
					String destinationString;
					for (int i = 1; i <= n; i++) {
						destinationString = params[i];
						demandId++;
						System.out.println("\t" + destinationString);
						sasDemandPrintWriter.println(demandId + "\t\t"
								+ sourceString + "\t\t" + destinationString
								+ "\t\t" + params[i + n]);
						// Load Dijkstra
						LinkState linkState = new LinkState();
						linkState.loadGraph(args[0]);
						linkState.initialize();
						source = linkState.nodesMap.get(sourceString);
						Node destination = linkState.nodesMap
								.get(destinationString);
						linkState.populateLeastCostPaths(source);

						int shortestPathHops = (linkState.leastCostPathTo(
								linkState.nodesMap.get(destinationString))
								.size() - 1);
						int maxHop = (int) Math.round(shortestPathHops
								+ (alpha * Math.log(shortestPathHops + 1))
								/ shortestPathHops);

						double minCost = destination.getMinCost();
						double minCostThreshold = minCost
								+ (beta * Math.log(minCost + 1));

						readablePrintWrite.println("ALPHA: " + alpha);
						readablePrintWrite.println("BETA: " + beta);

						printResults(source, destination, linkState,
								minCostThreshold, shortestPathHops, maxHop,
								demandId, readablePrintWrite);

						AllPaths allPaths = new AllPaths();
						allPaths.loadGraph(args[0]);

						ArrayList<ArrayList<Node>> pathList = allPaths
								.getAllPathsList(new ArrayList<Node>(),
										allPaths.nodesMap.get(sourceString),
										allPaths.nodesMap
												.get(destinationString), maxHop);

						Node previous = null;
						long boundPathCount = 0;

						for (ArrayList<Node> path : pathList) {
							previous = null;
							if (allPaths.getCost(path) < minCostThreshold) {
								boundPathCount++;
								pathId++;
								sasPathDemandPrintWriter.println(pathId + "\t"
										+ demandId + "\t\t" + sourceString
										+ "\t\t" + destinationString);
								for (Node node : path) {
									readablePrintWrite.print(">" + node);
									if (previous != null)
										sasKFactPrintWriter.println(pathId
												+ "\t"
												+ demandId
												+ "\t\t"
												+ previous
												+ "\t\t"
												+ node
												+ "\t\t"
												+ allPaths.nodesMap
														.get(sourceString)
												+ "\t\t"
												+ allPaths.nodesMap
														.get(destinationString)
												+ "\t\t1");
									previous = node;
								}
								readablePrintWrite.println("  	cost: "
										+ allPaths.getCost(path) + " path ID: "
										+ pathId);
							}
							sasKFactPrintWriter.flush();
							readablePrintWrite.flush();
							sasDemandPrintWriter.flush();
							sasPathDemandPrintWriter.flush();
						}

						readablePrintWrite.println("\nAll Path Count: "
								+ pathList.size());
						readablePrintWrite.println("Bound Path Count: "
								+ boundPathCount);
						readablePrintWrite
								.println("---------------------------------------------------------------------------------------------------------------------\n");

					}
				}
			}
			fileReader.close();
			sasKFactPrintWriter.close();
			readablePrintWrite.close();
			sasDemandPrintWriter.close();
			sasPathDemandPrintWriter.close();
			System.out.println("Program finished successfully!");
			System.out.println("See:");
			System.out.println("\t" + humanFileAddress);
			System.out.println("\t" + sasKFactFileAddress);
			System.out.println("\t" + sasPathDemandFileAddress);
			System.out.println("\t" + sasDemandFileAddress);
		} catch (Exception e) {
			System.out.println("Error Occured: " + e.getMessage());
			System.err
					.println("USAGE:\n java all_paths_SAS <graph file name> <path file name> <ALPHA> <BETA>\n Example:\njava all_paths_SAS ./network/node1.txt ./network/paths.txt 10 1.5");
			e.printStackTrace();
			e.printStackTrace();
		}

		try {
			Thread.sleep(8000);
		} catch (InterruptedException ex) {
			Thread.currentThread().interrupt();
		}
	}

	public static void printResults(Node source, Node destination,
			LinkState linkState, double minCostThreshold, int shortestPathHops,
			int maxHop, long demandId, PrintWriter printWriter) {

		printWriter.println("Source: " + source);
		printWriter.println("Destination: " + destination);
		printWriter.println("Demand ID: " + demandId);
		printWriter.println("Least Cost: " + destination.getMinCost());
		printWriter.println("Least Cost Threshold: " + minCostThreshold);
		printWriter.println("Shortest path Hops: " + shortestPathHops);
		printWriter.println("Max Path Hops: " + maxHop);
		printWriter.println("Path: " + linkState.leastCostPathTo(destination));

		printWriter.println("-------------------------------");
	}

	public static void main_(String[] args) {
		// ////////////
		try {
			File file;
			BufferedReader fileReader;

			file = new File("./results/PathOD.txt");
			fileReader = new BufferedReader(new FileReader(file));
			String line;
			String sourceString = null;
			while ((line = fileReader.readLine()) != null) {
				sourceString = null;
				String[] params = line.split("\\s+");
				if (params.length > 1) {
					for (String destinationString : params) {
						if (sourceString == null) {
							sourceString = destinationString;
							System.out.println(sourceString);
						} else {
							System.out.println("\t" + destinationString);
						}

					}
				}
			}
			fileReader.close();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}
